package com.yc.testupload.util;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

import java.util.Map;
import java.util.Properties;
import java.util.Set;

/**
 * Redis工具类
 * 提供Redis连接池管理和常用操作方法
 */
public class RedisUtil {

    private static final Logger logger = LogManager.getLogger(RedisUtil.class);
    
    // Redis连接池
    private static JedisPool jedisPool;
    
    // 静态初始化块，初始化连接池
    static {
        try {
            // 获取环境配置
            EnvironmentManager envManager = EnvironmentManager.getInstance();
            Properties props = envManager.getCurrentDatabaseConfig();
            
            // 从环境配置中读取Redis配置
            String host = props.getProperty("redis.host", "localhost");
            int port = Integer.parseInt(props.getProperty("redis.port", "6379"));
            String password = props.getProperty("redis.password", "");
            int database = Integer.parseInt(props.getProperty("redis.database", "0"));
            
            // 配置连接池
            JedisPoolConfig config = new JedisPoolConfig();
            config.setMaxTotal(100);  // 最大连接数
            config.setMaxIdle(20);    // 最大空闲连接数
            config.setMinIdle(5);     // 最小空闲连接数
            config.setMaxWaitMillis(10000); // 最大等待时间
            config.setTestOnBorrow(true); // 获取连接时测试连接是否可用
            config.setTestOnReturn(true); // 返回连接时测试连接是否可用
            
            // 初始化连接池
            if (password != null && !password.isEmpty()) {
                jedisPool = new JedisPool(config, host, port, 10000, password, database);
            } else {
                jedisPool = new JedisPool(config, host, port, 10000);
            }
            
            logger.info("Redis连接池初始化成功，host={}, port={}, database={}", host, port, database);
            
            // 检查并设置Redis持久化配置
            boolean enablePersistence = Boolean.parseBoolean(props.getProperty("redis.enable.persistence", "false"));
            if (enablePersistence) {
                configureRedisPersistence(props);
            }
            
        } catch (Exception e) {
            logger.error("Redis连接池初始化失败: {}", e.getMessage(), e);
        }
    }
    
    /**
     * 配置Redis持久化
     * @param props 配置属性
     */
    private static void configureRedisPersistence(Properties props) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            if (jedis != null) {
                String persistenceType = props.getProperty("redis.persistence.type", "RDB");
                logger.info("开始配置Redis持久化，类型: {}", persistenceType);
                
                // 配置RDB持久化
                if ("RDB".equalsIgnoreCase(persistenceType)) {
                    // 清除现有的save配置
                    jedis.configSet("save", "");
                    
                    // 设置新的save配置
                    String save900_1 = props.getProperty("redis.save.900.1", "900 1");
                    String save300_10 = props.getProperty("redis.save.300.10", "300 10");
                    String save60_10000 = props.getProperty("redis.save.60.10000", "60 10000");
                    
                    jedis.configSet("save", save900_1 + " " + save300_10 + " " + save60_10000);
                    logger.info("RDB持久化配置已设置: save {}, {}, {}", save900_1, save300_10, save60_10000);
                    
                    // 启用RDB压缩
                    jedis.configSet("rdbcompression", "yes");
                    logger.info("RDB压缩已启用");
                    
                    // 设置RDB文件名
                    jedis.configSet("dbfilename", "dump.rdb");
                    logger.info("RDB文件名设置为: dump.rdb");
                }
                
                // 可选：配置AOF持久化（如果需要）
                else if ("AOF".equalsIgnoreCase(persistenceType)) {
                    jedis.configSet("appendonly", "yes");
                    jedis.configSet("appendfsync", "everysec");
                    logger.info("AOF持久化已启用，同步策略: everysec");
                }
                
                // 测试持久化配置是否生效
                String saveConfig = jedis.configGet("save").get(1);
                logger.info("Redis持久化配置生效，当前save配置: {}", saveConfig);
                
            } else {
                logger.error("无法获取Redis连接，持久化配置失败");
            }
        } catch (Exception e) {
            logger.error("配置Redis持久化失败: {}", e.getMessage(), e);
        } finally {
            closeJedis(jedis);
        }
    }
    

    
    /**
     * 获取Redis连接
     * @return Redis连接实例
     */
    public static Jedis getJedis() {
        try {
            if (jedisPool != null) {
                return jedisPool.getResource();
            }
        } catch (Exception e) {
            logger.error("获取Redis连接失败: {}", e.getMessage(), e);
        }
        return null;
    }
    
    /**
     * 关闭Redis连接
     * @param jedis Redis连接实例
     */
    public static void closeJedis(Jedis jedis) {
        if (jedis != null) {
            try {
                jedis.close();
            } catch (Exception e) {
                logger.error("关闭Redis连接失败: {}", e.getMessage(), e);
            }
        }
    }
    
    /**
     * 设置字符串值
     * @param key 键
     * @param value 值
     * @return 设置是否成功
     */
    public static boolean set(String key, String value) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            if (jedis != null) {
                jedis.set(key, value);
                return true;
            }
        } catch (Exception e) {
            logger.error("设置Redis值失败 [{}]: {}", key, e.getMessage(), e);
        } finally {
            closeJedis(jedis);
        }
        return false;
    }
    
    /**
     * 设置字符串值并设置过期时间
     * @param key 键
     * @param value 值
     * @param expireTime 过期时间（秒）
     * @return 设置是否成功
     */
    public static boolean set(String key, String value, int expireTime) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            if (jedis != null) {
                // 设置带过期时间的值
                jedis.setex(key, expireTime, value);
                
                // 显式调用持久化命令，确保数据写入磁盘
                // 对于会话数据等重要信息，强制RDB快照
                try {
                    // 异步执行持久化，不阻塞当前操作
                    String saveResult = jedis.bgsave();
                    if ("Background saving started".equals(saveResult)) {
                        logger.info("成功触发Redis异步持久化，键: {}", key);
                    } else {
                        logger.warn("Redis持久化触发返回非预期结果: {}, 键: {}", saveResult, key);
                    }
                } catch (Exception pe) {
                    // 持久化失败不应影响主操作
                    logger.warn("触发Redis持久化失败，但数据已保存: {}", pe.getMessage());
                }
                
                return true;
            }
        } catch (Exception e) {
            logger.error("设置Redis值并过期时间失败 [{}]: {}", key, e.getMessage(), e);
        } finally {
            closeJedis(jedis);
        }
        return false;
    }
    
    /**
     * 获取字符串值
     * @param key 键
     * @return 值
     */
    public static String get(String key) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            if (jedis != null) {
                return jedis.get(key);
            }
        } catch (Exception e) {
            logger.error("获取Redis值失败 [{}]: {}", key, e.getMessage(), e);
        } finally {
            closeJedis(jedis);
        }
        return null;
    }
    
    /**
     * 删除键
     * @param key 键
     * @return 删除是否成功
     */
    public static boolean del(String key) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            if (jedis != null) {
                jedis.del(key);
                return true;
            }
        } catch (Exception e) {
            logger.error("删除Redis键失败 [{}]: {}", key, e.getMessage(), e);
        } finally {
            closeJedis(jedis);
        }
        return false;
    }
    
    /**
     * 设置键的过期时间
     * @param key 键
     * @param seconds 过期时间（秒）
     * @return 设置是否成功
     */
    public static boolean expire(String key, int seconds) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            if (jedis != null) {
                jedis.expire(key, seconds);
                return true;
            }
        } catch (Exception e) {
            logger.error("设置Redis键过期时间失败 [{}]: {}", key, e.getMessage(), e);
        } finally {
            closeJedis(jedis);
        }
        return false;
    }
    
    /**
     * 检查键是否存在
     * @param key 键
     * @return 是否存在
     */
    public static boolean exists(String key) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            if (jedis != null) {
                return jedis.exists(key);
            }
        } catch (Exception e) {
            logger.error("检查Redis键是否存在失败 [{}]: {}", key, e.getMessage(), e);
        } finally {
            closeJedis(jedis);
        }
        return false;
    }
    
    /**
     * 获取键的剩余过期时间（秒）
     * @param key 键
     * @return 剩余过期时间
     */
    public static long ttl(String key) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            if (jedis != null) {
                return jedis.ttl(key);
            }
        } catch (Exception e) {
            logger.error("获取Redis键过期时间失败 [{}]: {}", key, e.getMessage(), e);
        } finally {
            closeJedis(jedis);
        }
        return -2; // 返回-2表示键不存在或发生错误
    }
    
    /**
     * 存储Hash数据
     * @param key 键
     * @param field 字段
     * @param value 值
     * @return 操作结果
     */
    public static boolean hset(String key, String field, String value) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            if (jedis != null) {
                jedis.hset(key, field, value);
                return true;
            }
        } catch (Exception e) {
            logger.error("设置Redis Hash值失败 [{}:{}]: {}", key, field, e.getMessage(), e);
        } finally {
            closeJedis(jedis);
        }
        return false;
    }
    
    /**
     * 获取Hash字段的值
     * @param key 键
     * @param field 字段
     * @return 值
     */
    public static String hget(String key, String field) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            if (jedis != null) {
                return jedis.hget(key, field);
            }
        } catch (Exception e) {
            logger.error("获取Redis Hash值失败 [{}:{}]: {}", key, field, e.getMessage(), e);
        } finally {
            closeJedis(jedis);
        }
        return null;
    }
    
    /**
     * 获取Hash所有字段和值
     * @param key 键
     * @return Map对象
     */
    public static Map<String, String> hgetAll(String key) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            if (jedis != null) {
                return jedis.hgetAll(key);
            }
        } catch (Exception e) {
            logger.error("获取Redis Hash所有值失败 [{}]: {}", key, e.getMessage(), e);
        } finally {
            closeJedis(jedis);
        }
        return null;
    }
    
    /**
     * 删除Hash字段
     * @param key 键
     * @param fields 字段列表
     * @return 删除的字段数量
     */
    public static long hdel(String key, String... fields) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            if (jedis != null) {
                return jedis.hdel(key, fields);
            }
        } catch (Exception e) {
            logger.error("删除Redis Hash字段失败 [{}]: {}", key, e.getMessage(), e);
        } finally {
            closeJedis(jedis);
        }
        return 0;
    }
    
    /**
     * 添加元素到集合
     * @param key 键
     * @param values 值列表
     * @return 添加的元素数量
     */
    public static long sadd(String key, String... values) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            if (jedis != null) {
                return jedis.sadd(key, values);
            }
        } catch (Exception e) {
            logger.error("添加元素到Redis集合失败 [{}]: {}", key, e.getMessage(), e);
        } finally {
            closeJedis(jedis);
        }
        return 0;
    }
    
    /**
     * 从集合中移除元素
     * @param key 键
     * @param values 值列表
     * @return 移除的元素数量
     */
    public static long srem(String key, String... values) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            if (jedis != null) {
                return jedis.srem(key, values);
            }
        } catch (Exception e) {
            logger.error("从Redis集合移除元素失败 [{}]: {}", key, e.getMessage(), e);
        } finally {
            closeJedis(jedis);
        }
        return 0;
    }
    
    /**
     * 获取集合的所有元素
     * @param key 键
     * @return 元素集合
     */
    public static Set<String> smembers(String key) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            if (jedis != null) {
                return jedis.smembers(key);
            }
        } catch (Exception e) {
            logger.error("获取Redis集合所有元素失败 [{}]: {}", key, e.getMessage(), e);
        } finally {
            closeJedis(jedis);
        }
        return null;
    }
    
    /**
     * 检查元素是否在集合中
     * @param key 键
     * @param value 值
     * @return 是否存在
     */
    public static boolean sismember(String key, String value) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            if (jedis != null) {
                return jedis.sismember(key, value);
            }
        } catch (Exception e) {
            logger.error("检查元素是否在Redis集合中失败 [{}:{}]: {}", key, value, e.getMessage(), e);
        } finally {
            closeJedis(jedis);
        }
        return false;
    }
    
    /**
     * 增加计数器
     * @param key 键
     * @param delta 增加的值
     * @return 增加后的值
     */
    public static long incrBy(String key, long delta) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            if (jedis != null) {
                return jedis.incrBy(key, delta);
            }
        } catch (Exception e) {
            logger.error("增加Redis计数器失败 [{}]: {}", key, e.getMessage(), e);
        } finally {
            closeJedis(jedis);
        }
        return 0;
    }
    
    /**
     * 减少计数器
     * @param key 键
     * @param delta 减少的值
     * @return 减少后的值
     */
    public static long decrBy(String key, long delta) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            if (jedis != null) {
                return jedis.decrBy(key, delta);
            }
        } catch (Exception e) {
            logger.error("减少Redis计数器失败 [{}]: {}", key, e.getMessage(), e);
        } finally {
            closeJedis(jedis);
        }
        return 0;
    }
    
    /**
     * 关闭连接池
     */
    public static void closePool() {
        try {
            if (jedisPool != null) {
                jedisPool.close();
                logger.info("Redis连接池已关闭");
            }
        } catch (Exception e) {
            logger.error("关闭Redis连接池失败: {}", e.getMessage(), e);
        }
    }
    
    /**
     * 从Properties中获取属性值，如果不存在则返回默认值
     * @param props Properties对象
     * @param key 属性键
     * @param defaultValue 默认值
     * @return 属性值或默认值
     */
    private static String getProperty(Properties props, String key, String defaultValue) {
        if (props != null) {
            String value = props.getProperty(key);
            if (value != null && !value.trim().isEmpty()) {
                return value.trim();
            }
        }
        return defaultValue;
    }
}